package cn.jbolt.core.base;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.InterceptorManager;
import com.jfinal.config.Routes;
import com.jfinal.config.Routes.Route;
import com.jfinal.core.*;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * JBoltActionMapping
 */
public class JBoltActionMapping extends ActionMapping{

	public JBoltActionMapping(Routes routes) {
		super(routes);
	}
	@Override
	protected void buildActionMapping() {
		mapping.clear();
		Class<?> dc;
		InterceptorManager interMan = InterceptorManager.me();
		for (Routes routes : getRoutesList()) {
		for (Route route : routes.getRouteItemList()) {
			Class<? extends Controller> controllerClass = route.getControllerClass();
			Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass);

			boolean declaredMethods = routes.getMappingSuperClass()
					? controllerClass.getSuperclass() == Controller.class
					: true;

			Method[] methods = (declaredMethods ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());
			for (Method method : methods) {
				if (declaredMethods) {
					if (!Modifier.isPublic(method.getModifiers())) {
						continue;
					}

				} else {
					dc = method.getDeclaringClass();
					if (dc == Controller.class || dc == Object.class) {
						continue;
					}

				}

				if (method.getAnnotation(NotAction.class) != null) {
					continue ;
				}

				Interceptor[] actionInters = interMan.buildControllerActionInterceptor(routes.getInterceptors(), controllerInters, controllerClass, method);
				String controllerPath = route.getControllerPath();

				String methodName = method.getName();
				ActionKey ak = method.getAnnotation(ActionKey.class);
				String actionKey;
				if (ak != null) {
					actionKey = ak.value().trim();
					if ("".equals(actionKey)) {
						throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");
					}

					if (!actionKey.startsWith(SLASH)) {
						actionKey = controllerPath + SLASH + actionKey;
					}
				}
				else if (methodName.equals("index")) {
					actionKey = controllerPath;
				}
				else {
					actionKey = controllerPath.equals(SLASH) ? SLASH + methodName : controllerPath + SLASH + methodName;
				}

				Action action = new Action(controllerPath, actionKey, controllerClass, method, methodName, actionInters, route.getFinalViewPath(routes.getBaseViewPath()));
				if (mapping.put(actionKey, action) != null) {
					throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
				}
			}
		}
		}
		routes.clear();

		// support url = controllerPath + urlParas with "/" of controllerPath
		Action action = mapping.get("/");
		if (action != null) {
			mapping.put("", action);
		}
	}
}

